<!DOCTYPE HTML>
<html>
<head>
<title>arrow</title>
<meta charset="UTF-8"/>
</head>

<body>
    <canvas id='canvas' width="800" height="800"></canvas>
    <script>


const canvas = document.getElementById('canvas');
canvas.style.background = 'silver';
const ctx = canvas.getContext('2d');

// logic related constant
const GRAVITY = 0.2;
// const GRAVITY = 0;
const ANGLE_DIFF = Math.PI/40;
const STRENGTH_DIFF = 0.5;
const MAX_STRENGTH = 18;
const MIN_STRENGTH = 2;
const MAX_REMAIN = 20;

// init pos of the arrow
const SX = 50;
const SY = 500;

// button angle up and down
const BUTTON_ANGLE_UP_X = SX - 50;
const BUTTON_ANGLE_UP_Y = SY - 200;
const BUTTON_ANGLE_UP_X2 = SX + 50;
const BUTTON_ANGLE_UP_Y2 = SY - 100;

const BUTTON_ANGLE_DOWN_X = SX + 100;
const BUTTON_ANGLE_DOWN_Y = SY - 50;
const BUTTON_ANGLE_DOWN_X2 = SX + 200;
const BUTTON_ANGLE_DOWN_Y2 = SY + 50;


// generic button height
const BUTTON_HEIGHT = 80;

const BAR_STR_X = SX;
const BAR_STR_Y = SY + 60;
const BAR_STR_X2 = SX + 300;
const BAR_STR_Y2 = BAR_STR_Y + BUTTON_HEIGHT;
const BAR_STR_WIDTH = BAR_STR_X2 - BAR_STR_X ;
const BAR_STR_HEIGHT = BAR_STR_Y2 - BAR_STR_Y;

const BUTTON_SHOOT_X = SX;
const BUTTON_SHOOT_Y = BAR_STR_Y2 + 10;
const BUTTON_SHOOT_X2 = BUTTON_SHOOT_X + 300;
const BUTTON_SHOOT_Y2 = BUTTON_SHOOT_Y + BUTTON_HEIGHT;
const BUTTON_SHOOT_WIDTH = BUTTON_SHOOT_X2 - BUTTON_SHOOT_X;

// restart button is same level of shoot button
const BUTTON_RESTART_X = BUTTON_SHOOT_X2 + BUTTON_HEIGHT; // spacing same as height
const BUTTON_RESTART_Y = BUTTON_SHOOT_Y;
const BUTTON_RESTART_X2 = BUTTON_RESTART_X + 300;
const BUTTON_RESTART_Y2 = BUTTON_RESTART_Y + BUTTON_HEIGHT;
const BUTTON_RESTART_WIDTH = BUTTON_RESTART_X2 - BUTTON_RESTART_X;

let raf; // request animation frame
let angle = Math.PI / 4; // ANGLE_DIFF*3; // 45 degree
let strength = 10;
let targetList = []; // empty list first, init inside init()
let score = 0;
let remain = MAX_REMAIN; // how many arrow remains

const arrow = {
    x: SX,
    y: SY,
    vx: 0,
    vy: 0,
    radius: 15,
    color: 'red',
    moving: false,

    init() {
        this.x = SX;
        this.y = SY;

        // this.vx = 8;
        // this.vy = -23;
    },

    draw() {
        ctx.beginPath();
        ctx.arc(this.x | 0, this.y |0, this.radius, 0, Math.PI*2, true);
        ctx.closePath();
        ctx.fillStyle = this.color;
        ctx.fill();
    },

    isMoving() {
        if (0==this.vx && 0==this.vy) {
            return false;
        }
        return true;
    }, 

    logic() {
        if (false==this.moving) {
            return;
        }
        this.x += this.vx;
        this.y += this.vy;
        this.vy += GRAVITY; // + because larger y is downward

        if (this.x > canvas.width || this.x < 0) {
            this.x = SX;
            this.y = SY;
            this.vx = 0;
            this.vy = 0;
            this.moving = false;
        }
        if (this.y > SY || this.y < 0) {
            this.x = SX;
            this.y = SY;
            this.vx = 0;
            this.vy = 0;
            this.moving = false;
        }

        for (let i=0; i<targetList.length; i++) {
            score += targetList[i].check(this.x, this.y, this.radius);
        }
    },
}

class Target{

    constructor(x, y){
        this.x = x;
        this.y = y;
        this.height = 50;
        this.hit = false;
    }

    draw() {
        // console.log('OBJECT target draw');
        ctx.fillStyle = 'black';
        ctx.fillRect(this.x - 4, this.y, 8, this.height);

        if (this.hit==false) {
            ctx.fillStyle = 'silver'; // TODO canvas.background color
            ctx.fillRect(this.x - 3, this.y+1, 6, this.height-2);
        }

        // draw vertical line
        ctx.strokeStyle = 'black';
        ctx.beginPath();
        ctx.moveTo(this.x, this.y + this.height);
        ctx.lineTo(this.x, SY);
        ctx.closePath();
        ctx.stroke();
    }

    /**
     * @param {Number} cx  center of arrow
     * @param {Number} cy  center of arrow
     * @returns 0=miss, >=1 score 
     */
    check(cx, cy, radius) {
        if (this.hit==true) {
            return 0;
        }
        // this.x this.y this.height
        if((cx + radius)<(this.x - 3) || (cy + radius)<this.y || (cy - radius)>(this.y + this.height) || (cx - radius)>(this.x + 3)){
            return 0 ;
        }
        this.hit = true;
        return 1;
    }

}


function logicAllHit() {

    // when arrow is moving, do NOTHING
    if (arrow.vx!=0 && arrow.vy!=0) {
        return;
    }

    let allHit = true;
    for (let i=0; i<targetList.length; i++) {
        if (false == targetList[i].hit) {
            allHit = false;
            return;
        }
    }
    if (true==allHit) {
        initTarget();    
    }
}

function logic() {
    arrow.logic();
    logicAllHit();
}


function drawLine() {
    let x, y;
    const LINE_LEN = 100;
    x = SX;
    y = SY;
    ctx.fillStyle = 'black';
    ctx.fillRect(x, y, LINE_LEN, 1);  // x, y, width, height
    ctx.fillRect(x, y - LINE_LEN, 1, LINE_LEN);
}


// strength bar, rely on global var strength
function drawBar() {

    ctx.clearRect(0, BAR_STR_Y, canvas.clientWidth, BAR_STR_Y2 - BAR_STR_Y);

    let lineGrad;
    lineGrad = ctx.createLinearGradient(BAR_STR_X, BAR_STR_Y, BAR_STR_X2, BAR_STR_Y2);
    lineGrad.addColorStop(0, 'green');
    lineGrad.addColorStop(1, 'red');
    ctx.fillStyle = lineGrad;
    ctx.fillRect(BAR_STR_X, BAR_STR_Y, BAR_STR_WIDTH, BAR_STR_HEIGHT);

    ctx.fillStyle = 'black';
    ctx.fillText('力量 strength: ' + strength.toFixed(2), BAR_STR_X2 + 10, BAR_STR_Y2 - 10);

    let total = MAX_STRENGTH - MIN_STRENGTH ;
    let point = strength - MIN_STRENGTH;
    if (point < 0) {
        point = 0;
    }
    let x = ((point / total) * BAR_STR_WIDTH) | 0;
    // console.log('drawBar x=' + x);

    ctx.fillStyle = 'white';
    // width = 10 
    ctx.fillRect(BAR_STR_X + x-5, BAR_STR_Y, 10, BAR_STR_HEIGHT);

    ctx.fillStyle = 'black';
    ctx.fillRect(BAR_STR_X + x, BAR_STR_Y, 1, BAR_STR_HEIGHT);

}


function drawButtonShoot() {
    // 2-level button: shoot
    // assume 32px courier already set
    ctx.fillStyle = 'black';
    ctx.fillRect(BUTTON_SHOOT_X, BUTTON_SHOOT_Y, BUTTON_SHOOT_WIDTH, BUTTON_HEIGHT);
    ctx.fillStyle = 'grey';
    ctx.fillRect(BUTTON_SHOOT_X + 2, BUTTON_SHOOT_Y + 2, BUTTON_SHOOT_WIDTH - 4, BUTTON_HEIGHT - 4);
    ctx.fillStyle = 'black';
    ctx.fillText('发射 Shoot', BUTTON_SHOOT_X + 10, BUTTON_SHOOT_Y2 - 10);

}


function drawButtonRestart() {
    // 2-level button : restart
    // assume 32px courier already set
    ctx.fillStyle = 'black';
    ctx.fillRect(BUTTON_RESTART_X, BUTTON_RESTART_Y, BUTTON_RESTART_WIDTH, BUTTON_HEIGHT);
    ctx.fillStyle = 'grey';
    ctx.fillRect(BUTTON_RESTART_X + 2, BUTTON_RESTART_Y + 2, BUTTON_RESTART_WIDTH - 4, BUTTON_HEIGHT - 4);
    ctx.fillStyle = 'black';
    ctx.fillText('重来 Restart', BUTTON_RESTART_X + 10, BUTTON_RESTART_Y2 - 10);

}


// angle control
function drawControl() {
    // up-left arrow

    let x, y;

    ctx.beginPath();
    ctx.fillStyle = 'black';
    ctx.fillRect(BUTTON_ANGLE_UP_X, BUTTON_ANGLE_UP_Y, BUTTON_ANGLE_UP_X2-BUTTON_ANGLE_UP_X, BUTTON_ANGLE_UP_Y2-BUTTON_ANGLE_UP_Y);
    ctx.fillStyle = 'grey';
    ctx.fillRect(BUTTON_ANGLE_UP_X+1, BUTTON_ANGLE_UP_Y+1, BUTTON_ANGLE_UP_X2-BUTTON_ANGLE_UP_X-2, BUTTON_ANGLE_UP_Y2-BUTTON_ANGLE_UP_Y-2);

    ctx.fillStyle = 'black';
    ctx.fillRect(BUTTON_ANGLE_DOWN_X, BUTTON_ANGLE_DOWN_Y, BUTTON_ANGLE_DOWN_X2-BUTTON_ANGLE_DOWN_X, BUTTON_ANGLE_DOWN_Y2-BUTTON_ANGLE_DOWN_Y);
    ctx.fillStyle = 'grey';
    ctx.fillRect(BUTTON_ANGLE_DOWN_X+1, BUTTON_ANGLE_DOWN_Y+1, BUTTON_ANGLE_DOWN_X2-BUTTON_ANGLE_DOWN_X-2, BUTTON_ANGLE_DOWN_Y2-BUTTON_ANGLE_DOWN_Y-2);


    ctx.strokeStyle = 'black';
    ctx.fillStyle = 'black';
    // angle up arrow
    ctx.beginPath();
    ctx.moveTo(BUTTON_ANGLE_UP_X + 5, BUTTON_ANGLE_UP_Y + 5);
    ctx.lineTo(BUTTON_ANGLE_UP_X2 - 5, BUTTON_ANGLE_UP_Y2 - 5);
    // arrow
    ctx.moveTo(BUTTON_ANGLE_UP_X + 5, BUTTON_ANGLE_UP_Y + 5);
    ctx.lineTo(BUTTON_ANGLE_UP_X + 5, BUTTON_ANGLE_UP_Y + 25);
    ctx.lineTo(BUTTON_ANGLE_UP_X + 25, BUTTON_ANGLE_UP_Y + 5);
    ctx.closePath();
    ctx.stroke();
    ctx.fill();

    // angle down arrow
    ctx.beginPath();
    ctx.moveTo(BUTTON_ANGLE_DOWN_X2 - 5, BUTTON_ANGLE_DOWN_Y2 - 5);
    ctx.lineTo(BUTTON_ANGLE_DOWN_X + 5, BUTTON_ANGLE_DOWN_Y + 5);
    ctx.moveTo(BUTTON_ANGLE_DOWN_X2 - 5, BUTTON_ANGLE_DOWN_Y2 - 5);
    ctx.lineTo(BUTTON_ANGLE_DOWN_X2 - 25, BUTTON_ANGLE_DOWN_Y2 - 5);
    ctx.lineTo(BUTTON_ANGLE_DOWN_X2 - 5, BUTTON_ANGLE_DOWN_Y2 - 25);
    ctx.closePath();
    ctx.stroke();
    ctx.fill();
    

    // line cursor
    ctx.beginPath();
    ctx.strokeStyle = 'red';
    ctx.moveTo(SX, SY);
    x = SX + 80*Math.cos(angle);
    y = SY - 80*Math.sin(angle);
    ctx.lineTo(x, y);
    ctx.closePath();
    ctx.stroke();

}

// keep this for later
function old_drawControl() {
    let offCanvas;
    let ccc;  // context of offCanvas
    const MARGIN = 2;
    const OFF_HEIGHT = 100, OFF_WIDTH = 100;
    offCanvas = document.createElement('canvas'); // OFF_WIDTH, OFF_HEIGHT);
    offCanvas.width = OFF_WIDTH;
    offCanvas.height = OFF_HEIGHT;
    ccc = offCanvas.getContext('2d');
    ccc.save();
    // ccc.rotate(Math.PI / 4); // + or - ? + is clockwise
    // ccc.rotate(-3 * Math.PI / 4); // + or - ? + is clockwise
    ccc.fillStyle = 'black';
    ccc.fillRect(0, 0, OFF_WIDTH, OFF_HEIGHT);
    ccc.fillStyle = 'blue';
    // draw a horizontal line
    ccc.fillRect(MARGIN + OFF_WIDTH / 2, OFF_HEIGHT/2, OFF_WIDTH / 2 - 2*MARGIN - 10, 1);
    ccc.beginPath();
    ccc.moveTo(OFF_WIDTH - MARGIN,  OFF_HEIGHT / 2);
    ccc.lineTo(OFF_WIDTH - MARGIN - 10, OFF_HEIGHT / 2 - 10);
    ccc.lineTo(OFF_WIDTH - MARGIN - 10, OFF_HEIGHT / 2 + 10);
    ccc.closePath();
    ccc.fill();
    // ccc.rotate(Math.PI / 4); // pi / 4 = 45 degrees
    ccc.restore();


    ctx.save();
    ctx.rotate(-3 * Math.PI / 4);
    ctx.drawImage(offCanvas, SX + 200, SY - 150);
    ctx.restore();

}

function drawTarget() {
    for (let i=0; i<targetList.length; i++) {
        targetList[i].draw();
    }
    // draw a platform
    ctx.fillStyle = 'black';
    ctx.fillRect(SX + 200, SY, 500, 1);
    
}

function drawStatus() {
    let status = '';
    if (remain<=0) {
        status = 'Game Over';
    }

    ctx.fillStyle = 'black';
    ctx.font = '32px courier';
    ctx.fillText('分数 Score: ' + score, 50, 50);
    ctx.fillText('剩下 Remain: ' + remain + '  ' + status, 50, 100);

}

function draw() {
    logic();
    ctx.clearRect(0, 0, canvas.clientWidth, SY + 20); // canvas.height);
    arrow.draw();
    drawLine();
    drawControl();
    // drawBar(); // str bar
    drawTarget();
    drawStatus();  // score, remain, game over etc
    raf = window.requestAnimationFrame(draw);
}

canvas.addEventListener('mouseover', (e) => {
    raf = window.requestAnimationFrame(draw);
});

canvas.addEventListener('mouseout', (e) => {
    window.cancelAnimationFrame(raf);
});



function angleUp() {
    // console.log('ANGLE UP');
    if(angle < Math.PI/2){
        angle += ANGLE_DIFF;
    }
    if(angle >= Math.PI/2){
        angle = Math.PI/2;
    }
}

function angleDown() {
    // console.log('ANGLE DOWN');
    if(angle > 0){
        angle -= ANGLE_DIFF;
    }
    if(angle <= 0){
        angle = 0;
    }
}

function strengthUp() {
    strength += STRENGTH_DIFF;
    if (strength > MAX_STRENGTH) {
        strength = MAX_STRENGTH;
    }
    drawBar();
    // console.log('Str UP: ' + strength);
}

function strengthDown() {
    strength -= STRENGTH_DIFF;
    if (strength < MIN_STRENGTH) {
        strength = MIN_STRENGTH;
    }
    drawBar();
    // console.log('Str DOWN: ' + strength);
}


function shootArrow() {
    if (arrow.isMoving()) {
        return; 
    }
    remain --;  // reduce one arrow
    if (remain <= 0) {
        remain = 0;
        return;
    }
    // let strength = 20;
    arrow.init(); // set zero first
    arrow.vx = strength * Math.cos(angle);
    arrow.vy = -strength * Math.sin(angle);
    arrow.moving = true;
}

/**
 * 
 * @param {MouseEvent} event 
 */
function onClick(event){
    let x = event.offsetX;
    let y = event.offsetY;

    // console.log('mouse x, y:' + x + ', ' + y);

    if (x >= BUTTON_ANGLE_UP_X && x <= BUTTON_ANGLE_UP_X2 
        && y >= BUTTON_ANGLE_UP_Y && y <= BUTTON_ANGLE_UP_Y2) {
        angleUp();
        return;
    }
    if (x >= BUTTON_ANGLE_DOWN_X && x <= BUTTON_ANGLE_DOWN_X2 
        && y >= BUTTON_ANGLE_DOWN_Y && y <= BUTTON_ANGLE_DOWN_Y2) {
        angleDown();
        return;
    }
    // click the arrow (the ball itself)
    if(x >= SX - 15 && x <= SX + 15 && y <= SY + 15 && y >= SY - 15){
        shootArrow();
        return;
    }
    if(x >= BUTTON_SHOOT_X && x <= BUTTON_SHOOT_X2 && y >= BUTTON_SHOOT_Y && y <= BUTTON_SHOOT_Y2) {
        shootArrow();
        return;
    }
    if(x >= BUTTON_RESTART_X && x <= BUTTON_RESTART_X2 && y >= BUTTON_RESTART_Y && y <= BUTTON_RESTART_Y2) {
        init();
        draw();
        return;
    }

    // give a little more margin
    if (x >= BAR_STR_X - 2 && x <= BAR_STR_X2 + 2 && y >= BAR_STR_Y && y <= BAR_STR_Y2) {

        strength = (MIN_STRENGTH + (MAX_STRENGTH - MIN_STRENGTH) * (x - BAR_STR_X) / BAR_STR_WIDTH);
        // DO not use toFixed here, it will become strength
        // just use it before fillText
        // strength = strength.toFixed(2);
        if (strength > MAX_STRENGTH) {
            strength = MAX_STRENGTH;
        }
        if (strength < MIN_STRENGTH) {
            strength = MIN_STRENGTH;
        }
        drawBar();
        return;
    }
}


/**
 * 
 * @param {KeyboardEvent} event 
 */
function onKey(event){
    // console.log('key: ' + event.key);
    if (event.key == 'i' || event.key == 'ArrowUp') {
        angleUp();
        return;
    }
    if (event.key == 'k' || event.key == 'ArrowDown') {
        angleDown();
        return;
    }
    if (event.key == 'j' || event.key == 'ArrowLeft') {
        strengthDown();
        return;
    }
    if (event.key == 'l' || event.key == 'ArrowRight') {
        strengthUp();
        return;
    }
    if (event.key == ' ') {
        shootArrow();
        return;
    }
}

function initTarget() {
    targetList = [];
    // TODO use for loop to create
    let y;


    for (let i=0; i<4; i++) {
        // y (= [100 - 500]
        y = Math.random() * 200 + 100;
        targetList[i] = new Target(SX+300+i*100, y);

    }
    // targetList[0] = new Target(400, 500);
    // targetList[1] = new Target(500, 500);
    // targetList[2] = new Target(600, 500);
    // targetList[3] = new Target(700, 500);
}

function init() {
    score = 0;
    remain = MAX_REMAIN;
    arrow.init();
    // shall we reset the strength and angle ??? NO?
    initTarget();
}

init();

canvas.addEventListener("click", onClick);
window.addEventListener("keydown", onKey, false);

arrow.init();
arrow.draw();

draw();
drawBar();
drawButtonShoot();
drawButtonRestart();



    </script>
</body>

</html>

